/*---------------------------------------------------------------------------
    $Workfile		: AndroidDotManager.cpp $

    Author			: Joseph Chacko, Ajith Joseph
    Last $Modtime	: 16/11/2011 
    Last $Revision	: 1 $
	Remark			: None
    $History		: AndroidDotManager.cpp$
---------------------------------------------------------------------------*/

#include "AndroidDotNetManager.h"
#include "AndroidDotNetSettingsForm.h"
#include "NewAndroidProject.h"
#include "AboutAndroidDotNet.h"
#include "Connect.h"
#include "NewAndroidProject.h"

using namespace System;
using namespace System::Diagnostics;
using namespace System::IO;
using namespace System::Runtime::Serialization;
using namespace System::Xml;
using namespace System::Xml::Serialization;
using namespace System::Windows::Forms;


AndroidDotNET::CAndroidDotNetManager::CAndroidDotNetManager(EnvDTE80::DTE2^ DTE2)
{
	m_AndroidDotNetSettings= gcnew CAndroidDotNetSettings();
	m_NewAndroidProjectInfo= gcnew NewAndroidProjectInfo();
	m_AndroidTargetSettings= gcnew AndroidTargetSettings();
	m_NewAndroidTSArray= gcnew System::Collections::Generic::List<AndroidTargetSettings^>();
	m_DTE2=DTE2;
}

bool AndroidDotNET::CAndroidDotNetManager ::LoadAllAndroidTargetPlatforms(System::String^ strSDKLocation)
	{
		try
		{
			//To get all the Subdirectories from the platform directories
			if(strSDKLocation[strSDKLocation->Length-1]!='\\')
			{
				strSDKLocation+="\\";
			}
			array<System::String^>^ SubDirs= Directory::GetDirectories(strSDKLocation+"platforms");
			for(int i=0;i<SubDirs->Length;i++)
			{
				AndroidTargetSettings^ TargetSettings=gcnew AndroidTargetSettings();

				//To get the Android version
				array<Char>^PlatformSpliter = {'\\'};
				array<String^>^ PlatformTokens =SubDirs[i]->Split(PlatformSpliter);
				TargetSettings->m_strFolderName=PlatformTokens[PlatformTokens->Length-1];

				//To get the content of each directory
				System::String^ strFileContent=File::ReadAllText(SubDirs[i]+"\\Source.Properties");
				array<Char>^chars = {'\n'};
				array<String^>^ Tokens =strFileContent->Split(chars);
				for(int j=0;j<Tokens->Length;j++)
				{
					if(Tokens[j]->Contains("AndroidVersion.ApiLevel"))
					{
						String^ strAPIInfo=Tokens[j];
						array<Char>^chars = {'='};	
						array<String^>^ APITokens=strAPIInfo->Split(chars);
						TargetSettings->m_strAPI=APITokens[1];
					}
					else if(Tokens[j]->Contains("Platform.Version"))
					{
						String^ VersionInfo=Tokens[j];
						array<Char>^chars = {'='};	
						array<String^>^ VersionTokens=VersionInfo->Split(chars);
						TargetSettings->m_strPlatform=VersionTokens[1];
						TargetSettings->m_strTargetName="Android "+TargetSettings->m_strPlatform;
					}
					else if(Tokens[j]->Contains("{"))
					{

					}
				}
				m_NewAndroidTSArray->Add(TargetSettings);
			}
			return true;
		}
		catch(...)
		{
			return false;
		}
	}

/* Create New Android Project*/
bool AndroidDotNET::CAndroidDotNetManager::InvokeNewAndroidProject(void)
{
	NewAndroidProjectInfo^ m_NewAndroidProjectInfo=gcnew NewAndroidProjectInfo();
	try
	{
		//check skd location is set
		if(m_AndroidDotNetSettings->m_strSDKLocation=="")
		{
			System::Windows::Forms::MessageBox::Show("SDK Location does not set. Please set SDK location from the menu \"AndroidStudio->AndroidStudio Settings\"");
		}
		else
		{
			NewAndroidProjectInfo^ ProjectInfo= gcnew NewAndroidProjectInfo();
			ProjectInfo->m_NewAndroidTSArray=m_NewAndroidTSArray;
			NewAndroidProjectForm^ SettingsForm= gcnew NewAndroidProjectForm(ProjectInfo);
			if(SettingsForm->ShowDialog()==System::Windows::Forms::DialogResult::OK)
			{
				switch(SettingsForm->m_CREATE_PROJECT_OPTION)
				{
				case  CREATE_NEW_PROJECT:
					{
					NewAndroidProjectInfo^ NewProjectInfo=SettingsForm->GetNewAndroidProjectInfo();			
					
					//Read target from Registry
					System::String^ strTarget;
					try
					 {
						 RegistryKey^ key = Registry::CurrentUser->CreateSubKey("Software\\Tek-Tips.Info\\Android\\");
						 strTarget= key->GetValue("DEFAULT_TARGET_VERSION")->ToString();
						 key->Close();
					 }
					 catch (...)
					 {
						 strTarget= "";
					 }
					 System::String^ cmdLineParms=NewProjectInfo->GetAndroidCreateCmdLineParms(strTarget);
					 if(System::Diagnostics::Process::Start(m_AndroidDotNetSettings->m_strSDKLocation+"\\tools\\android",cmdLineParms)->WaitForExit(10000))
					 {
						 m_CurrentProjectPath=NewProjectInfo->m_strLocation +"\\"+ NewProjectInfo->m_strProjectName;
						 if(CreateAndDisplayProjectInSolutionExplorer(NewProjectInfo->m_strLocation +"\\"+ NewProjectInfo->m_strProjectName))
						 {
							 System::Windows::Forms::MessageBox::Show("New Anroid Project Created Successfully..","AndroidStudio");
						 }
						 else
						 {
							 System::Windows::Forms::MessageBox::Show("Failed to load the new project to Solution Explorer..");
							 return false;
						 }
						 return true;
					 }
					 else
					 {
						 System::Windows::Forms::MessageBox::Show("Failed to create new android project","AndroidStudio");
						 return false;
					 }
					 break;
					}
				case  CREATE_PROJECT_FROM_EXISTING_SOURCE:
					{
						NewAndroidProjectInfo^ NewProjectInfo=SettingsForm->GetNewAndroidProjectInfo();	
						System::String^ cmd;
						System::String^ strTarget;
					try
					 {
						 RegistryKey^ key = Registry::CurrentUser->CreateSubKey("Software\\Tek-Tips.Info\\Android\\");
						 strTarget= key->GetValue("DEFAULT_TARGET_VERSION")->ToString();
						 key->Close();
					 }
					 catch (...)
					 {
						 strTarget= "";
					 }
						 cmd=NewProjectInfo->GetAndroidUpdateCmdLineParms(strTarget);
						 System::Diagnostics::Process::Start(m_AndroidDotNetSettings->m_strSDKLocation+"tools\\android",cmd)->WaitForExit(10000);
						 m_CurrentProjectPath=NewProjectInfo->m_strExistingLocation;
						 if(CreateAndDisplayProjectInSolutionExplorer(NewProjectInfo->m_strExistingLocation))
						 {
							 System::Windows::Forms::MessageBox::Show("New Anroid Project Created Successfully..","AndroidStudio");
						 }
						 else
						 {
							 System::Windows::Forms::MessageBox::Show("Failed to load the new project to Solution Explorer..");
							 return false;
						 }
					}
					break;
				}
			}
		}
	}
	catch(Exception^ Ex)
	{
		System::Windows::Forms::MessageBox::Show("Failed to create new android project. Reason: " + Ex->Message,"AndroidStudio");
		return false;
	}
	return true;
}

//Invoke Open Android Project to open the Android Project
bool AndroidDotNET::CAndroidDotNetManager::InvokeNewAndroidProjectOpenMenu(void)
{
	OpenFileDialog ^ objFileBrowserDialog = gcnew OpenFileDialog();
	objFileBrowserDialog->DefaultExt="*.sln"; 
	objFileBrowserDialog->Filter="Sln files (*.sln)|*.sln";
	if(objFileBrowserDialog->ShowDialog()== DialogResult::OK)
	{
		LoadAndDisplayInSolutionExplorer(objFileBrowserDialog->FileName );
	}
	return true;
}
bool AndroidDotNET::CAndroidDotNetManager::InvokeNewAndroidProjectOpenFolder(void)
{
	try
	{
		System::String^ filename;
		FolderBrowserDialog^ mydialog = gcnew FolderBrowserDialog();
		if (mydialog->ShowDialog() == DialogResult::OK)
		{
			filename = mydialog->SelectedPath;
			CreateProjectInSolutionExplorer(filename);
			m_CurrentProjectPath=filename;
		}
	}
	catch(Exception^ Ex)
	{
		MessageBox::Show(Ex->Message);
	}
	return true;
}

// Invoke Anrdoid SDK Compile to compile this project
int AndroidDotNET::CAndroidDotNetManager::InvokeCompileCommand()
{
	try
	{
		System::Diagnostics::ProcessStartInfo^ AndroidCompileInfo = gcnew System::Diagnostics::ProcessStartInfo();
		AndroidCompileInfo->UseShellExecute=false;
		AndroidCompileInfo->WorkingDirectory=m_CurrentProjectPath;
	
		AndroidCompileInfo->FileName="ant.bat";
		AndroidCompileInfo->Arguments="compile";
		System::Diagnostics::Process^ process=gcnew System::Diagnostics::Process();
		process->StartInfo=AndroidCompileInfo;
		process->Start();
	}
	catch(Exception^ Ex)
	{
		MessageBox::Show(Ex->Message);
	}
	return 0;
}

// Invoke Anrdoid SDK Compile to Run this project
int AndroidDotNET::CAndroidDotNetManager::InvokeRunCommand(void)
{
	//to get selected project name
	array<String^>^ strTempProjectPath;
	array<Char>^divider = {'\\'};
	strTempProjectPath=m_CurrentProjectPath->Split(divider);
	System::String^ strProjectName=strTempProjectPath[strTempProjectPath->Length-1];
	System::String^ strSDKLocation;
	try
	{
		RegistryKey^ key = Registry::CurrentUser->CreateSubKey("Software\\Tek-Tips.Info\\Android\\");
		strSDKLocation= key->GetValue("DEFAULT_SDK_LOCATION")->ToString();
		key->Close();
	}
	catch (...)
	{
		strSDKLocation= "";
	}
	if(strSDKLocation=="")
	{
		System::Windows::Forms::MessageBox::Show("Set SDK Location ","Error...");
	}
	else
	{
		System::Diagnostics::ProcessStartInfo^ Info=gcnew System::Diagnostics::ProcessStartInfo();
		Info->WorkingDirectory=strSDKLocation+"platform-tools";
		Info->FileName="adb.exe";
		Info->Arguments="install "+ m_CurrentProjectPath+"\\bin\\"+strProjectName+"-debug-unaligned.apk";
		System::Diagnostics::Process^ p=gcnew System::Diagnostics:: Process();
		p->StartInfo=Info;
		p->Start();
	}
	return 0;
}


// Invoke Anrdoid SDK  to Debug this project
int AndroidDotNET::CAndroidDotNetManager::InvokeDebugCommand(void)
{
	System::Diagnostics::ProcessStartInfo^ AndroidDebugInfo = gcnew System::Diagnostics::ProcessStartInfo();
	AndroidDebugInfo->WorkingDirectory=m_CurrentProjectPath;
	AndroidDebugInfo->FileName="ant.bat";
	AndroidDebugInfo->Arguments="debug";
	System::Diagnostics::Process^ process=gcnew System::Diagnostics::Process();
	process->StartInfo=AndroidDebugInfo;
	process->Start();
	return 0;
}
int AndroidDotNET::CAndroidDotNetManager::InvokeSettingsCommand(void)
{
	AndroidDotNetSettingsForm^ SettingsForm= gcnew AndroidDotNetSettingsForm(m_AndroidDotNetSettings);
	if(SettingsForm->ShowDialog()==System::Windows::Forms::DialogResult::OK)
	{
		m_AndroidDotNetSettings= SettingsForm->GetAndroidDotNetSettings();
		SaveAndroidSettings();
	}
	return 0;
}
int AndroidDotNET::CAndroidDotNetManager::InvokeAndroidEmulatorCommand(void)
{
	System::String^ strSDKLocation;
	try
	{
		RegistryKey^ key = Registry::CurrentUser->CreateSubKey("Software\\Tek-Tips.Info\\Android\\");
		strSDKLocation= key->GetValue("DEFAULT_SDK_LOCATION")->ToString();
		key->Close();
	}
	catch (...)
	{
		strSDKLocation= "";
	}
	if(strSDKLocation=="")
	{
		System::Windows::Forms::MessageBox::Show("Set SDK Location ","Error...");
	}
	else
	{
		System::Diagnostics::ProcessStartInfo^ EmulatorInfo=gcnew System::Diagnostics::ProcessStartInfo();
		EmulatorInfo->WorkingDirectory=strSDKLocation+"tools";
		EmulatorInfo->FileName="emulator-arm.exe";
		EmulatorInfo->Arguments="-avd AndroidStudio -scale 100dpi";//AndroidStudio is a local avdname, Created by AndroidStudio
		System::Diagnostics::Process^ p=gcnew System::Diagnostics::Process();
		p->StartInfo=EmulatorInfo;
		p->Start();
	}
	return 0;
}
int AndroidDotNET::CAndroidDotNetManager::InvokeNewEmulatorCommand(void)//Create new AVD.
{
	System::String^ strSDKLocation;
	System::String^ strAVDTArget;
	try
	{
		RegistryKey^ key = Registry::CurrentUser->CreateSubKey("Software\\Tek-Tips.Info\\Android\\");
		strSDKLocation= key->GetValue("DEFAULT_SDK_LOCATION")->ToString();
		strAVDTArget=key->GetValue("DEFAULT_TARGET_VERSION")->ToString();
		key->Close();
	}
	catch (...)
	{
		strSDKLocation= "";
		strAVDTArget="";
	}
	if(strSDKLocation=="")
	{
		System::Windows::Forms::MessageBox::Show("Set SDK Location ","Error...");
	}
	else if(strAVDTArget=="")
	{
		System::Windows::Forms::MessageBox::Show("Set SDK target Version ","Error...");
	}
	else
	{
		System::Diagnostics::ProcessStartInfo^ EmulatorInfo=gcnew System::Diagnostics::ProcessStartInfo();
		EmulatorInfo->WorkingDirectory=strSDKLocation+"tools";
		EmulatorInfo->FileName="Android";
		EmulatorInfo->Arguments="create avd -n AndroidStudio -t "+  strAVDTArget +" -f";//AndroidStudio is the new avdname
		System::Diagnostics::Process^ p=gcnew System::Diagnostics::Process();
		p->StartInfo=EmulatorInfo;
		p->Start();
	}
	return 0;
}
int AndroidDotNET::CAndroidDotNetManager::InvokeAboutAndroidCommand(void)
{
	AboutAndroidDotNet^ AboutForm=gcnew AboutAndroidDotNet();
	AboutForm->ShowDialog();
	return 0;
}

bool AndroidDotNET::CAndroidDotNetManager::LoadAndroidSDKSettings(void)
{ 
	//Load the settings from file
	//deserialize the file to the variable m_AndroidDotNetSettings
	//ANDROID_DOT_NET_DEFAULT_SETTINGS_FILE
	System::IO::Stream^ stream;
	try
	{
		System::String^ strDataPath=GetAssemblyDirectory(); //Changed to Installed Directory TOM
		strDataPath+="\\";

		//SoapFormatter^ formatter = gcnew SoapFormatter;
		XmlSerializer^ formatter = gcnew XmlSerializer(CAndroidDotNetSettings::typeid);
		stream= System::IO::File::Open(strDataPath+ANDROID_DOT_NET_DEFAULT_SETTINGS_FILE, System::IO::FileMode::Open );

		//formatter = new BinaryFormatter();
		m_AndroidDotNetSettings = dynamic_cast<CAndroidDotNetSettings^>(formatter->Deserialize( stream ));
		stream->Close();
		LoadAllAndroidTargetPlatforms(m_AndroidDotNetSettings->m_strSDKLocation);
		return true;
	}
	catch(...)
	{
		LoadAllAndroidTargetPlatforms(m_AndroidDotNetSettings->m_strSDKLocation);
		if(stream)
		{
			stream->Close();
		}
		return false;
	}
	return true;
}

bool AndroidDotNET::CAndroidDotNetManager::SaveAndroidSettings(void)
{
	//ANDROID_DOT_NET_DEFAULT_SETTINGS_FILE
	System::String^ strDataPath=GetAssemblyDirectory(); //Changed to Installed Directory 
	strDataPath+="\\";
	Stream^ stream;
	try
	{
		//Opens a file and serializes the object into it in binary format.
	    stream= File::Open(strDataPath+ANDROID_DOT_NET_DEFAULT_SETTINGS_FILE, FileMode::Create );

		//SoapFormatter^ formatter = gcnew SoapFormatter;
		XmlSerializer^ formatter = gcnew XmlSerializer(CAndroidDotNetSettings::typeid);
	
		formatter->Serialize( stream, m_AndroidDotNetSettings );
		stream->Close();
		return true;
	}
	catch(System::Exception^ )
	{
		//System::Windows::Forms::MessageBox::Show(Ex->Message);
		if(stream)
		{
			stream->Close();
		}
		return false;
	}
	return true;
}

System::String^ AndroidDotNET::CAndroidDotNetManager::GetAssemblyDirectory(void)
{
	System::String^ StrPath=System::Reflection::Assembly::GetExecutingAssembly()->Location;
	return Path::GetDirectoryName(StrPath);
}

bool AndroidDotNET::CAndroidDotNetManager::CreateAndDisplayProjectInSolutionExplorer(System::String^ OpenFolderLoad)
{
	try
	{
		array<System::String^>^ AllFiles=Directory::GetFiles(OpenFolderLoad,"*.*",SearchOption::AllDirectories);
		System::IO::Directory;
		array<Char>^chars = {'\\'};
		array<String^>^ Tokens =OpenFolderLoad->Split(chars);
		Solution^ NewSolution=m_DTE2->Solution;
		System::String^ file;
		
		NewSolution->Create(OpenFolderLoad,Tokens[Tokens->Length-1]);
		for(int i=0;i<AllFiles->Length;i++)
		{
			file=AllFiles[i];
			System::String^ fileType=Path::GetExtension(file);
			if(fileType==".sln")
			{
				LoadAndDisplayInSolutionExplorer(file);
				return true;
			}
			if(fileType==".suo")
			{
				File::Delete(file);
			}
			else
			{
				m_DTE2->ItemOperations->AddExistingItem(AllFiles[i]);
			}
		}
		NewSolution->SaveAs(Tokens[Tokens->Length-1]);
		m_DTE2->Documents->CloseAll(EnvDTE::vsSaveChanges::vsSaveChangesYes);	
		return true;
	}
	catch(Exception^ ex)
	{
		MessageBox::Show(ex->Message);
		return false;
	}
}

bool AndroidDotNET::CAndroidDotNetManager::CreateProjectInSolutionExplorer(System::String^ OpenFolderLoad)
{
	array<System::String^>^ AllFiles=Directory::GetFiles(OpenFolderLoad,"*.*",SearchOption::AllDirectories);
	System::IO::Directory;
	array<Char>^chars = {'\\'};
	array<String^>^ Tokens =OpenFolderLoad->Split(chars);
	Solution^ NewSolution=m_DTE2->Solution;
	NewSolution->Create(OpenFolderLoad,Tokens[Tokens->Length-1]);
	System::String^ file;
	for(int i=0;i<AllFiles->Length;i++)
	{
		file=AllFiles[i];
		System::String^ fileType=Path::GetExtension(file);
		if(fileType==".sln")
		{
			LoadAndDisplayInSolutionExplorer(file);
			return true;
		}
		if(fileType==".suo")
		{
			File::Delete(file);
		}
		else
		{
			m_DTE2->ItemOperations->AddExistingItem(AllFiles[i]);
		}
	}
	NewSolution->SaveAs(Tokens[Tokens->Length-1]);
	m_DTE2->Documents->CloseAll(EnvDTE::vsSaveChanges::vsSaveChangesYes);
	return true;
}
bool AndroidDotNET::CAndroidDotNetManager::LoadAndDisplayInSolutionExplorer(System::String^ OpenSolution)
{
	//m_CurrentProjectPath="\""+System::IO::FileInfo(OpenSolution).DirectoryName+"\"";
	m_CurrentProjectPath=System::IO::FileInfo(OpenSolution).DirectoryName;
	m_DTE2->Solution->Open(OpenSolution);
	return true;
}
